package com.jingdianjichi.project.infra.basic.service.impl;

import com.jingdianjichi.project.common.entity.PageResult;
import com.jingdianjichi.project.common.enums.SubjectInfoTypeEnum;
import com.jingdianjichi.project.infra.basic.entity.EsSubjectFields;
import com.jingdianjichi.project.infra.basic.entity.SubjectInfoEs;
import com.jingdianjichi.project.infra.basic.es.EsIndexInfo;
import com.jingdianjichi.project.infra.basic.es.EsRestClient;
import com.jingdianjichi.project.infra.basic.es.EsSearchRequest;
import com.jingdianjichi.project.infra.basic.es.EsSourceData;
import com.jingdianjichi.project.infra.basic.service.SubjectEsService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * ClassName:SubjectEsServiceImpl
 * Package:com.jingdianjichi.subject.infra.basic.service.impl
 * Description:
 *
 * @Author fst
 * @Create 2025/1/5 0:28
 * @Version 1.0
 */

@Service
@Slf4j
public class SubjectEsServiceImpl implements SubjectEsService
{

    @Override
    public boolean insert(SubjectInfoEs subjectInfoEs)
    {
        EsSourceData esSourceData =new EsSourceData();

        Map<String,Object> data =convertTOEsSourceData(subjectInfoEs);

        esSourceData.setDocId(subjectInfoEs.getDocId().toString());

        esSourceData.setData(data);

        return EsRestClient.insertDoc(getEsIndexInfo(), esSourceData);

    }


    private Map<String,Object> convertTOEsSourceData(SubjectInfoEs subjectInfoEs)
    {
        Map<String,Object> data=new HashMap<>();

        data.put(EsSubjectFields.SUBJECT_ID,subjectInfoEs.getSubjectId());
        data.put(EsSubjectFields.SUBJECT_ANSWER,subjectInfoEs.getSubjectAnswer());
        data.put(EsSubjectFields.SUBJECT_NAME,subjectInfoEs.getSubjectName());
        data.put(EsSubjectFields.SUBJECT_TYPE,subjectInfoEs.getSubjectType());
        data.put(EsSubjectFields.CREATE_USER,subjectInfoEs.getCreateUser());
        data.put(EsSubjectFields.CREATE_TIME,subjectInfoEs.getCreateTime());
        data.put(EsSubjectFields.DOC_ID,subjectInfoEs.getDocId());

        return data;
    }

    private EsIndexInfo getEsIndexInfo()
    {
        EsIndexInfo esIndexInfo = new EsIndexInfo();
        esIndexInfo.setClusterName("b428039ad1f2");
        esIndexInfo.setIndexName("subject_index");

        return esIndexInfo;
    }

    @Override
    public PageResult<SubjectInfoEs> querySubjectList(SubjectInfoEs subjectInfoEs)
    {
        PageResult<SubjectInfoEs> pageResult = new PageResult<>();
        EsSearchRequest esSearchRequest = createSearchListQuery(subjectInfoEs);

        SearchResponse searchResponse = EsRestClient.searchWithTermQuery(getEsIndexInfo(), esSearchRequest);

        List <SubjectInfoEs> subjectInfoEsList = new ArrayList<>();

        SearchHits hits = searchResponse.getHits();

        if(hits==null || hits.getHits()==null)
        {
            pageResult.setPageNo(subjectInfoEs.getPageNo());
            pageResult.setPageSize(subjectInfoEs.getPageSize());
            pageResult.setRecords(subjectInfoEsList);
            pageResult.setTotal(0);
            return pageResult;
        }

        SearchHit[] hitsList = hits.getHits();

        for(SearchHit hit:hitsList)
        {
            SubjectInfoEs subjectInfoEs1 =convert(hit);

            if(Objects.nonNull(subjectInfoEs1))
            {
                subjectInfoEsList.add(subjectInfoEs1);
            }
        }

        pageResult.setPageNo(subjectInfoEs.getPageNo());
        pageResult.setPageSize(subjectInfoEs.getPageSize());
        pageResult.setRecords(subjectInfoEsList);
        long value = hits.getTotalHits().value;
        pageResult.setTotal((int) value);
        return pageResult;
    }

    private SubjectInfoEs convert(SearchHit hit)
    {

        Map<String, Object> sourceAsMap = hit.getSourceAsMap();

        if(CollectionUtils.isEmpty(sourceAsMap))
        {
            return null;
        }

        SubjectInfoEs subjectInfoEs=new SubjectInfoEs();

        subjectInfoEs.setSubjectId(Long.valueOf(sourceAsMap.get(EsSubjectFields.SUBJECT_ID).toString()));
        subjectInfoEs.setSubjectAnswer(sourceAsMap.get(EsSubjectFields.SUBJECT_ANSWER).toString());
        subjectInfoEs.setSubjectName(sourceAsMap.get(EsSubjectFields.SUBJECT_NAME).toString());
        subjectInfoEs.setSubjectType(Integer.valueOf(sourceAsMap.get(EsSubjectFields.SUBJECT_TYPE).toString()));
        subjectInfoEs.setDocId(Long.valueOf(sourceAsMap.get(EsSubjectFields.DOC_ID).toString()));

        subjectInfoEs.setScore(new BigDecimal(String.valueOf(hit.getScore())).
                multiply(new BigDecimal(100.00)).setScale(2, RoundingMode.HALF_UP));

        Map<String, HighlightField> highlightFields = hit.getHighlightFields();

        HighlightField subjectNameField = highlightFields.get(EsSubjectFields.SUBJECT_NAME);

        if(Objects.nonNull(subjectNameField))
        {
            Text[] fragments = subjectNameField.getFragments();
            StringBuilder subjectNameBuilder = new StringBuilder();

            for (Text fragment : fragments)
            {
                subjectNameBuilder.append(fragment.string());
            }

            subjectInfoEs.setSubjectName(subjectNameBuilder.toString());
        }

        HighlightField subjectAnswerField = highlightFields.get(EsSubjectFields.SUBJECT_ANSWER);

        if(Objects.nonNull(subjectAnswerField))
        {
            Text[] fragments = subjectAnswerField.getFragments();
            StringBuilder subjectAnswerBuilder = new StringBuilder();

            for (Text fragment : fragments)
            {
                subjectAnswerBuilder.append(fragments);
            }

            subjectInfoEs.setSubjectAnswer(subjectAnswerBuilder.toString());
        }

        return subjectInfoEs;

    }

    private EsSearchRequest createSearchListQuery(SubjectInfoEs subjectInfoEs)
    {
        EsSearchRequest esSearchRequest = new EsSearchRequest();
        BoolQueryBuilder bq = QueryBuilders.boolQuery();

        MatchQueryBuilder SubjectNameQueryBuilder = QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_NAME, subjectInfoEs.getKeyWord());

        //设置优先级
        SubjectNameQueryBuilder.boost(2);

        bq.should(SubjectNameQueryBuilder);

        MatchQueryBuilder SubjcetAnswerQueryBuilder = QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_ANSWER, subjectInfoEs.getKeyWord());

        bq.should(SubjcetAnswerQueryBuilder);

        MatchQueryBuilder subjectTypeQueryBuilder = QueryBuilders.matchQuery(EsSubjectFields.SUBJECT_TYPE, SubjectInfoTypeEnum.BRIEF.getCode());

        bq.must(subjectTypeQueryBuilder);

        bq.minimumShouldMatch(1);

        HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
        highlightBuilder.preTags("<span style =\"color:red\">");
        highlightBuilder.postTags("</span>");
        esSearchRequest.setBq(bq);
        esSearchRequest.setHighlightBuilder(highlightBuilder);
        esSearchRequest.setFields(EsSubjectFields.FIELD_QUERY);
        esSearchRequest.setFrom((subjectInfoEs.getPageNo()-1)*subjectInfoEs.getPageSize());
        esSearchRequest.setSize(subjectInfoEs.getPageSize());
        esSearchRequest.setNeedScroll(false);

        return esSearchRequest;
    }
}
